home *** CD-ROM | disk | FTP | other *** search
/ 10,000 Great Games / 10,000 Great Games.iso / Product / 66 / data1.cab / Source_Files / Src / Movable.cpp < prev    next >
C/C++ Source or Header  |  2000-01-16  |  9KB  |  432 lines

  1. #include "stdafx.h"
  2.  
  3. cPush::cPush(cPush **list, fix duration, fix _vx, fix _vy, fix _ax, fix _ay)
  4. {
  5.     vx = _vx;
  6.     vy = _vy;
  7.     ax = _ax;
  8.     ay = _ay;
  9.         
  10.     timeleft = duration;
  11.     ptimer = 0;
  12.     
  13.     add((cList **)list);
  14. }
  15.  
  16. cMovable::cMovable(cProperties *_orig)
  17.         : cAudible(_orig)
  18. {
  19.     pushes = 0;
  20.     stop_movement();
  21.     
  22.     resting = FALSE;        
  23.     horizontal_friction = orig->params->get_bool("*HORIZONTAL_FRICTION", TRUE);
  24.  
  25.     bounce_loss = orig->params->get_int("*BOUNCE_LOSS", 3);
  26.     one_time_bounce = orig->params->get_bool("*ONE_TIME_BOUNCE", FALSE);
  27.     
  28.     last_bounce_y = MAXINT;
  29. }
  30.  
  31. cMovable::~cMovable()
  32. {
  33.     pushes->delete_list();
  34. }
  35.  
  36. int cMovable::control()
  37. {
  38.     fix dx, dy, dv, dt;
  39.     
  40.     // Do changing of picture
  41.     
  42.     cAudible::control();
  43.     
  44.     // Save old variables
  45.     
  46.     ox = x, oy = y;
  47.     
  48.     // Compute time difference
  49.     
  50.     dt = vtimer.delta();
  51.     
  52.     // Do movement in x direction
  53.     
  54.     dv = ax * dt;
  55.     dx = (vx + (dv >> 1)) * dt;
  56.     vx += dv;
  57.     
  58.     // Do movement in y direction
  59.     
  60.     dv = ay * dt;
  61.     dy = (vy + (dv >> 1)) * dt;
  62.     vy += dv;
  63.     
  64.     // Handle pushes
  65.     
  66.     cPush *n;
  67.     int kill;
  68.     
  69.     for (cPush *p = pushes; p != 0; p = n)
  70.     {
  71.         n = (cPush *)p->next;
  72.         
  73.         // First get time difference
  74.         
  75.         dt = p->ptimer.delta();
  76.         
  77.         // Check if push is ending here
  78.         
  79.         if (dt > p->timeleft)
  80.         {
  81.             dt = p->timeleft;
  82.             kill = TRUE;
  83.         }
  84.         else
  85.         {
  86.             p->timeleft -= dt;
  87.             kill = FALSE;
  88.         }
  89.         
  90.         // Do movement in x direction
  91.         
  92.         dv = p->ax * dt;
  93.         dx += (p->vx + (dv >> 1)) * dt;
  94.         p->vx += dv;
  95.         
  96.         // Do movement in y direction
  97.         
  98.         dv = p->ay * dt;
  99.         dy += (p->vy + (dv >> 1)) * dt;
  100.         p->vy += dv;
  101.         
  102.         // Check if there's some time left
  103.         
  104.         if (kill)
  105.         {
  106.             // Add aquired speed permanently
  107.             
  108.             vx += p->vx, vy += p->vy;
  109.             
  110.             // Remove this object
  111.             
  112.             delete p;
  113.         }
  114.     }
  115.     
  116.     // Set new position
  117.     
  118.     if (dx != (fix)0 || dy != (fix)0)
  119.         set_position(fx + dx, fy + dy);
  120.  
  121.     return TRUE;
  122. }
  123.  
  124. int cMovable::check_resting_on_boundaries(cLine *obj, cDisplayable *bound)
  125. {
  126.     // The function computes the boundary lines (for obj) before and after
  127.     // movement computed by control(). It forms a square with the new
  128.     // boundary line as base and the height of the previous boundary line
  129.     // as height.
  130.     //
  131.     // After that it searches for lines that fall in the area and picks out
  132.     // the first the object would encounter. The object is placed correctly
  133.     // interpolated on this line. This function only detects lines when the
  134.     // object is going down.
  135.     
  136.     ASSERT(obj != 0);
  137.     
  138.     // Get old (oy1) and new (y1, x1, x2) boundary line for object
  139.     
  140.     int oy1 = oy - obj->y1, y1 = y - obj->y1;
  141.     
  142.     int x1 = x + obj->x1, x2 = x + obj->x2;
  143.     sort2(x1, x2);
  144.     
  145.     // Consider only the case: oy1 >= y1, we're going down
  146.     
  147.     if (oy1 >= y1)
  148.     {
  149.         int y_max = MININT;
  150.             
  151.         // Loop through displayables
  152.  
  153.         for (cDisplayable *d = bound; d != 0; d = (cDisplayable *)d->next)
  154.         {
  155.             // Loop trough lines
  156.             
  157.             for (cLine *l = d->line_bounds; l != 0; l = (cLine *)l->next)
  158.             {
  159.                 int lx1 = d->x + l->x1, lx2 = d->x + l->x2, ly1 = d->y - l->y1;
  160.  
  161.                 sort2(lx1, lx2);
  162.                 
  163.                 if (lx2 >= x1 && x2 >= lx1 && oy1 >= ly1 && ly1 >= y1)
  164.                     y_max = ly1;                
  165.             }
  166.         }
  167.         
  168.         // If there was a boundary, set the object on this boundary
  169.                 
  170.         if (y_max > MININT)
  171.         {
  172.             // Put object on the edge
  173.             
  174.             set_position(fx, (fix)(y_max + obj->y1));
  175.             
  176.             // We're on boundary
  177.             
  178.             return TRUE;
  179.         }
  180.     }
  181.     
  182.     // We're not on boundary
  183.     
  184.     return FALSE;
  185. }
  186.  
  187. void cMovable::bounce_on_boundaries()
  188. {
  189.     // This function is an extension from check_resting_on_boundaries,
  190.     // it handles the bouncing and resting of objects on platforms.
  191.     
  192.     // Bounce on walls
  193.     
  194.     if (!x_on_screen())
  195.         vx = -vx / bounce_loss;
  196.     
  197.     // Check if we fell onto something
  198.     
  199.     if (orig->line != 0 
  200.         && (!one_time_bounce || oy < last_bounce_y)
  201.         && check_resting_on_boundaries(line_bounds, structures)
  202.        )
  203.     {    
  204.         // Modify horizontal speed
  205.  
  206.         if (horizontal_friction)
  207.         {
  208.             if (abs(vx) < (fix)10)
  209.                 vx = 0;
  210.             else if (!is_x_pushed())
  211.                 new_x_push(0.5, 0, -vx);
  212.         }
  213.         
  214.         // Modify vertical speed, when velocity is smaller than 70 upwards
  215.         // (approx 10 pixels total movement) set status to resting
  216.  
  217.         if ((vy >= (fix)0 && vy < (fix)70) || resting)
  218.             vy = 0, resting = TRUE;
  219.         else
  220.             vy = -vy / bounce_loss;
  221.         
  222.         last_bounce_y = y;        
  223.     }
  224.     else
  225.     {
  226.         resting = FALSE;
  227.     }
  228.  
  229.     // Set vertical acceleration
  230.  
  231.     ay = GRAVITY;
  232. }
  233.  
  234. void cMovable::move_objects_on_boundaries(cLine *obj, cDisplayable *bound)
  235. {
  236.     // The function computes the boundary lines (for obj) before and after
  237.     // movement computed by control(). It forms a square with the new
  238.     // boundary line as base and the height of the previous boundary line
  239.     // as height.
  240.     //
  241.     // After that it searches for lines that fall in the area and moves all
  242.     // objects by the amount this movable moved.
  243.     
  244.     ASSERT(obj != 0);
  245.     
  246.     // Get old and new (y1, y2, x1, x2) boundary lines for object
  247.     
  248.     int y1 = oy - obj->y1, y2 = y - obj->y1;
  249.     sort2(y1, y2);
  250.     
  251.     int x1 = x + obj->x1, x2 = x + obj->x2;
  252.     sort2(x1, x2);
  253.     
  254.     // Loop through displayables
  255.     
  256.     for (cDisplayable *d = bound; d != 0; d = (cDisplayable *)d->next)
  257.     {
  258.         // Loop trough lines
  259.         
  260.         for (cLine *l = d->line_bounds; l != 0; l = (cLine *)l->next)
  261.         {
  262.             int lx1 = d->x + l->x1, lx2 = d->x + l->x2, ly1 = d->y - l->y1;
  263.             
  264.             sort2(lx1, lx2);
  265.             
  266.             if (lx2 >= x1 && x2 >= lx1 && y1 <= ly1 && ly1 <= y2)
  267.             {
  268.                 d->make_dirty();
  269.                 d->set_position(d->fx + (fix)(x - ox), fy - (fix)obj->y1 + (fix)l->y1);
  270.                 d->make_dirty();
  271.             }
  272.         }
  273.     }
  274. }
  275.  
  276. cDisplayable *cMovable::check_radial_boundaries(cCircle *obj, cDisplayable *bound, int (*callback)(cMovable *, cDisplayable *, cCircle *, cCircle *), cDisplayable *ignore, int reposition)
  277. {
  278.     // This function determines if there is any object in "bound"
  279.     // that is in radius of circle(s) "obj" and calls callback (if
  280.     // not zero) for every object. It returns the closest object.
  281.     
  282.     // Distance that object travelled in x and y direction
  283.     
  284.     int dx = x - ox, dy = y - oy;
  285.     
  286.     // Distance squared
  287.     
  288.     int dd = d_square(dx, dy);
  289.     
  290.     // Closest object, minimum distance found and position of that object
  291.     
  292.     cDisplayable *closest = 0, *last_callback = 0;
  293.     int d_min = MAXINT, closest_x = 0, closest_y = 0;
  294.     
  295.     // Loop through circles
  296.     
  297.     for (cCircle *o = obj; o != 0; o = (cCircle *)o->next)
  298.     {
  299.         // Start position
  300.         
  301.         int sx = ox + o->x, sy = oy - o->y;
  302.         
  303.         // End position
  304.         
  305.         int ex = x + o->x, ey = y - o->y;
  306.         
  307.         // Loop through objects
  308.             
  309.         for (cDisplayable *d = bound; d != 0; d = (cDisplayable *)d->next)
  310.         {
  311.             // Loop through circles for every object
  312.             
  313.             if (d != this && d != ignore)
  314.                 for (cCircle *c = d->circle_bounds; c != 0; c = (cCircle *)c->next)
  315.                 {
  316.                     // Locus of circle of object d, circle c
  317.                     
  318.                     int cx = d->x + c->x, cy = d->y - c->y;
  319.                     
  320.                     // Point of closest approach fraction: t/dd of whole vector
  321.                     
  322.                     int t = (cx - sx) * dx + (cy - sy) * dy;
  323.                     
  324.                     // If t < 0 or t > length of vector choose end points, else
  325.                     // choose closest point
  326.                     
  327.                     int qx, qy;
  328.                     
  329.                     if (t <= 0)
  330.                         qx = sx, qy = sy;
  331.                     else if (t >= dd)
  332.                         qx = ex, qy = ey;
  333.                     else
  334.                         qx = sx + t*dx/dd, qy = sy + t*dy/dd;
  335.                     
  336.                     // Compute distance
  337.                     
  338.                     int dist = d_square(cx - qx, cy - qy);
  339.                     
  340.                     // Check if it is in range
  341.                     
  342.                     if (dist < square(o->radius + c->radius))
  343.                     {
  344.                         if (callback != 0 && (last_callback == d || !callback(this, d, o, c)))
  345.                             continue;
  346.  
  347.                         last_callback = d;
  348.  
  349.                         if (dist - c->radius < d_min)
  350.                         {
  351.                             d_min = dist - c->radius;
  352.                             
  353.                             closest = d;
  354.                             closest_x = qx;
  355.                             closest_y = qy;
  356.                         }
  357.                     }
  358.                 }
  359.         }
  360.     }
  361.     
  362.     // Move to closest position
  363.     
  364.     if (reposition && closest != 0)
  365.         set_position(closest_x, closest_y);
  366.     
  367.     // Return closest object
  368.     
  369.     return closest;
  370. }
  371.  
  372. void cMovable::add_position(fix dx, fix dy)
  373. {
  374.     set_position(fx + dx, fy + dy);
  375. }
  376.  
  377. void cMovable::add_angular_position(fix d, fix angle)
  378. {
  379.     set_position(fx + d * cos(angle), fy + d * sin(angle));
  380. }
  381.  
  382. fix cMovable::get_speed(fix angle)
  383. {
  384.     return vx * cos(angle) + vy * sin(angle);
  385. }
  386.  
  387. void cMovable::set_angular_speed(fix v, fix angle)
  388.     vx = v * cos(angle);
  389.     vy = v * sin(angle);
  390. }
  391.  
  392. void cMovable::add_angular_speed(fix v, fix angle)
  393. {
  394.     vx += v * cos(angle);
  395.     vy += v * sin(angle);
  396. }
  397.  
  398. fix cMovable::get_acceleration(fix angle)
  399. {
  400.     return ax * cos(angle) + ay * sin(angle);
  401. }
  402.  
  403. void cMovable::set_angular_acceleration(fix a, fix angle)
  404. {
  405.     ax = a * cos(angle);
  406.     ay = a * sin(angle);
  407. }
  408.  
  409. void cMovable::add_angular_acceleration(fix a, fix angle)
  410. {
  411.     ax += a * cos(angle);
  412.     ay += a * sin(angle);
  413. }
  414.  
  415. int cMovable::is_x_pushed()
  416. {
  417.     for (cPush *p = pushes; p != 0; p = (cPush *)p->next)
  418.         if (p->vx != (fix)0 || p->ax != (fix)0)
  419.             return TRUE;
  420.  
  421.     return FALSE;
  422. }
  423.  
  424. int cMovable::is_y_pushed()
  425. {
  426.     for (cPush *p = pushes; p != 0; p = (cPush *)p->next)
  427.         if (p->vy != (fix)0 || p->ay != (fix)0)
  428.             return TRUE;
  429.  
  430.     return FALSE;
  431. }